package org.example.test;

import org.example.domain.Author;
import org.example.domain.Book;
import org.junit.Test;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author liuga
 * @date 2022/10/10 15:40
 * Description:使用 stream 流对集合进行各种各样的操作
 */
public class StreamTest02 {

    @Test
    public void test1() {
        List<Author> authors = getAuthors();
        //把集合转换成流
        authors.stream()
                //将流中的重复元素给去除掉
                .distinct()
                //过滤筛选 需要的数据
                .filter(author -> author.getAge() < 18)
                //终结操作 遍历打印
                .forEach(author -> System.out.println(author.getName()));
    }

    /**
     * map
     * 双列集合
     */
    @Test
    public void test2() {
        Map<String, Integer> map = new HashMap<>();
        map.put("蜡笔小新", 19);
        map.put("黑子", 17);
        map.put("日向翔阳", 16);
        Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();

        stream.
                filter(stringIntegerEntry -> stringIntegerEntry.getValue() > 16)
                .forEach(stringIntegerEntry -> System.out.println(stringIntegerEntry.getKey() + ":" + stringIntegerEntry.getValue()));

    }

    /**
     * filter
     * 打印所有姓名长度大于 1 的作家的姓名
     */
    @Test
    public void test3() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .filter(author -> author.getName().length() > 1)
                .forEach(author -> System.out.println(author.getName()));
    }

    /**
     * map
     * <p>
     * 可以把对流中的元素进行计算或转换。
     * <p>
     * 例如：打印所有作家的姓名
     */
    @Test
    public void test4() {
        List<Author> authors = getAuthors();
        //返回字符串 将流中的对象 转换成字符串
        authors.stream()
                .map(Author::getAge).map(age -> age + 100).
                forEach(System.out::println);
    }

    /**
     * distinct
     * <p>
     * 可以去除流中的重复元素。
     * <p>
     * 例如：打印所有作家的姓名，并且要求其中不能有重复元素。
     */
    @Test
    public void test5() {
        List<Author> authors = getAuthors();
        //返回字符串 将流中的对象 转换成字符串
        authors.stream()
                //基于重写的equals 去重
                .distinct().
                forEach(System.out::println);
    }

    /**
     * sorted
     * <p>
     * 可以对流中的元素进行排序。
     * <p>
     * 例如：对流中的元素按照年龄进行降序排序，并且要求不能有重复的元素。
     */
    @Test
    public void test6() {
        List<Author> authors = getAuthors();
        /*authors.stream()
                .distinct()
                .sorted()
                .forEach(System.out::println);*/
        authors.stream().distinct().sorted(Comparator.comparingInt(Author::getAge)).forEach(System.out::println);
    }

    /**
     * limit
     * <p>
     * 可以设置流的最大长度，超出的部分将被抛弃。
     * <p>
     * 例如：对流中的元素按照年龄进行降序排序，并且要求不能有重复的元素, 然后打印其中年龄最大的两个作家的姓名。
     */
    @Test
    public void test7() {
        List<Author> authors = getAuthors();
        authors.stream().distinct().sorted().limit(2).forEach(System.out::println);
    }

    /**
     * skip
     * <p>
     * 跳过流中的前 n 个元素，返回剩下的元素
     * <p>
     * 例如：打印除了年龄最大的作家外的其他作家，要求不能有重复元素，并且按照年龄降序排序。
     */
    @Test
    public void test8() {
        List<Author> authors = getAuthors();
        authors.stream().distinct().sorted().skip(2).forEach(System.out::println);
    }

    /**
     * flatMap
     * <p>
     * map 只能把一个对象转换成另一个对象来作为流中的元素。而 flatMap 可以把一个对象转换成多个对象作为流中的元素。
     * <p>
     * 例一：打印所有书籍的名字。要求对重复的元素进行去重。
     */
    @Test
    public void test9() {
        List<Author> authors = getAuthors();
        /*authors.stream()
                .flatMap(new Function<Author, Stream<Book>>() {
                    @Override
                    public Stream<Book> apply(Author author) {
                        return author.getBooks().stream();
                    }
                })
                .distinct()
                .forEach(o -> System.out.println(o.getName()));*/
        /*authors.stream()//Stream<Author>
                .flatMap(author -> author.getBooks().stream())//Stream<Book>
                .distinct()
                .forEach(o -> System.out.println(o.getName()));*/
// 打印现有数据的所有分类。要求对分类进行去重。不能出现这种格式：哲学,爱情 爱情
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
                .distinct()
                .forEach(System.out::println);
    }

    @Test
    public void test10() {
        List<Author> authors = getAuthors();
        long count = authors.stream()
                .distinct()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .count();
        System.out.println(count);

    }

    @Test
    public void test11() {
        List<Author> authors = getAuthors();
/*

        Optional<Integer> max = authors.stream()
                .distinct()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .map(Book::getScore)
                .max(Comparator.comparingInt(score -> score));
        System.out.println(max.get());
*/


        Optional<Integer> min = authors.stream()
                .distinct()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .map(Book::getScore)
                .min(Comparator.comparingInt(score -> score));
        System.out.println(min.get());
    }

    @Test
    public void test12() {
        List<Author> authors = getAuthors();
        // 获取一个存放所有作者名字的List or Set集合。
     /*   Set<String> names = authors.stream()
                .map(Author::getName)
                .collect(Collectors.toSet());
        System.out.println(names);*/
// 获取一个Map集合，map的key为作者名，value为List<Book>

        Map<String, List<Book>> map = authors.stream()
                .distinct()
                .collect(Collectors.toMap(Author::getName, author -> {
                    // List<Book> 这是 map 的value
                    return author.getBooks().stream()
                            .distinct()//将value去重
                            .collect(Collectors.toList());
                }));
        //p29
        System.out.println(map);
    }


    @Test
    public void test13() {
        List<Author> authors = getAuthors();
        Optional<Author> min = authors.stream().min((o1, o2) -> o1.getAge() - o2.getAge());
        min.ifPresent(o -> System.out.println(o.getName()));

        Optional<Author> first = authors.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).findFirst();
        first.ifPresent(o -> System.out.println(o.getName()));

    }


    @Test
    public void test14() {
        List<Author> authors = getAuthors();
        //使用 reduce 求所有作者年龄的和
//         Integer reduce = authors.stream().distinct().map(Author::getAge).reduce(0, (result, element) -> result + element);
//         System.out.println(reduce);

        //使用 reduce 求所有作者中年龄的最大值
        //Integer max = authors.stream().distinct().map(Author::getAge).reduce(0, (r, e) -> r < e ? e : r);
        //System.out.println(max);
        //使用 reduce 求所有作者中年龄的最小值
//        Integer min = authors.stream().distinct()
//                .map(Author::getAge)
//                .reduce(Integer.MAX_VALUE, (r, e) ->r > e ? e : r
//        );
//        System.out.println(min);

        Optional<Integer> reduce = authors.stream().map(Author::getAge).reduce((r, e) -> r < e ? e : r);
        reduce.ifPresent(System.out::println);
    }

    @Test
    public void test15() {
        List<Author> authors = getAuthors();
        Stream<Author> authorStream = authors.stream();
       /* authorStream.filter(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getAge()>17;
            }
        }.and(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getName().length()>1;
            }
        })).forEach(author -> System.out.println(author));*/
        authorStream.forEach(new Consumer<Author>() {
            @Override
            public void accept(Author author) {
                System.out.println(author.getAge());
            }
        }.andThen(new Consumer<Author>() {
            @Override
            public void accept(Author author) {
                System.out.println(author.getName());
            }
        }));
    }

    @Test
    public void test16() {

        List<Author> authors = getAuthors();
        authors.stream()
                .map(Author::getAge)
                .map(age -> age + 10)
                .filter(age -> age > 18)
                .map(age -> age + 2)
                .forEach(System.out::println);
        authors.stream()
                .map(Author::getAge)
                .mapToInt(age -> age+10)
                .filter(age -> age > 18)
                .map(age -> age + 2)
                .forEach(System.out::println);
    }
    @Test
    public   void test17() {
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer sum = stream.parallel()
                //中间操作 调试的方法
                .peek(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer num) {
                        System.out.println(num+Thread.currentThread().getName());
                    }
                })
                .filter(num -> num > 5)
                .reduce((result, ele) -> result + ele)
                .get();
        System.out.println(sum);
    }



    private static List<Author> getAuthors() {
        //数据初始化
        Author author = new Author(1L, "蒙多", 33, "一个从菜刀中明悟哲理的祖安人", null);
        Author author2 = new Author(2L, "亚拉索", 15, "狂风也追逐不上他的思考速度", null);
        Author author3 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);
        Author author4 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);

        //书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L, "刀的两侧是光明与黑暗", "哲学,爱情", 88, "用一把刀划分了爱恨"));
        books1.add(new Book(2L, "一个人不能死在同一把刀下", "个人成长,爱情", 99, "讲述如何从失败中明悟真理"));

        books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
        books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
        books2.add(new Book(4L, "吹或不吹", "爱情,个人传记", 56, "一个哲学家的恋爱观注定很难把他所在的时代理解"));

        books3.add(new Book(5L, "你的剑就是我的剑", "爱情", 56, "无法想象一个武者能对他的伴侣这么的宽容"));
        books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));
        books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author, author2, author3, author4));
        return authorList;
    }

}
